框架

v5.2.1 修复报告:二级源 VIX 回退失效 + 债券腿"盘中伪收盘"

scripts/dkanalysis.py L0-2 分支的回退守卫写成:

optimization · 资产·机制 · optimization/报告/v5.2.1 二级源回退与债券盘中价修复报告_2026-09-26.md · 7863 B

v5.2.1 修复报告:二级源 VIX 回退失效 + 债券腿"盘中伪收盘"

生成时间:2026-09-26T01:20:00+08:00

触发:2026-09-25「执行开盘日任务」首次运行(run_id 20260925T235746+0800)出现 L0 由「正常」回退为「降级」 + 排版 2 项告警

性质:两个真实代码缺陷(非数据源问题、非数据缺失)

结论:已修复 + 备份 + 回归测试 + 重发验证;arch_check 10/10 ✔、doc_sync_check 全绿、测试全绿

状态:已落地生产库


一、缺陷 P1-1|二级源 VIX 回退在"二级源比目标日更新"时整段失效

症状

  • 目标日 = 2026-09-24,权威源 FRED VIXCLS 仅到 2026-09-22(未发布)。
  • 二级源 数据/vix_daily.json 已含 2026-09-25 的 T+0 延迟报价(CBOE),且 2026-09-23/09-24 已由 CBOE 官方日线 CSV 权威覆盖。
  • 结果:L0-2 = 无法评估(note: "VIX 未更新到目标日(最近 2026-09-22)")→ L0 汇总 = 降级(存在无法评估项),模拟盘 state_snapshot.L0 随之变为「降级」。
  • 与预期相反:二级源明明已有目标日的权威值,却完全没被用上。

根因

scripts/dkanalysis.py L0-2 分支的回退守卫写成:

ds, closes, _srcs = dkaux.vix_series(aux)   # ds = 全部日期升序,含 09-25
tkey = str(target.date())                   # '2026-09-24'
if ds and ds[-1] == tkey:                   # ← 错:要求“序列末项 == 目标日”
    ...

T+0 延迟报价天生会比目标日更新(黄金目标停留在 09-24 时,VIX 已有 09-25 盘中值), 序列末项变成 2026-09-25 → 守卫不成立 → 回退整段失效。 上一次(20260925T153432+0800)恰好因为 VIX 序列末项也是 09-24 才"看起来正常", 属于偶合通过。

修复

upto = [d for d in ds if d <= tkey]         # 只看目标日及之前
if upto and upto[-1] == tkey:               # 只要“目标日在序列内”
    ...
    prev_used = upto[-2] if len(upto) >= 2 else None   # 前值取“目标日之前”而非序列倒数第二
    vix_src = _SRC_LABEL.get(dkaux.vix_source_of(aux, tkey) or "", "二级源")

附带改进:来源标签改为按实际源映射(cboe_csv → CBOE 官方日线 CSV、 cboe_delayed → CBOE 延迟报价(T+0)、fred → FRED VIXCLS、cboe_delayed_derived → 反推), 不再一律写"延迟报价(T+0)"从而低估权威性。

红线保持(回归测试断言)

  • 权威源已有目标日值时绝不被二级源顶替(vix_src == "FRED VIXCLS");
  • 无二级源时行为不变(仍 无法评估);
  • 前值为反推值时必须标 [待验证];为权威 CSV 时不应再标。

验证(重发后真实数据)

L0-2 VIX 跳升 | 正常 | 单日 +3.2%, 三日 +5.4% | 来源:CBOE 官方日线 CSV;权威源尚未发布到目标日,暂用二级源回退
L0 汇总 = 正常(L0-3 可评估)    aux_sources: vix_used=CBOE 官方日线 CSV, l0_aux_used=true

二、缺陷 P1-2|债券腿把当日"盘中未完成"日线当收盘永久并入

症状

  • 抓取时刻 = 2026-09-25 23:57 CST = 15:57 UTC = 美股 09-25 盘中(开盘约 2.5 小时)。
  • 东财日线 push2his 接口在盘中即返回当日未完成中间价:

['2026-09-22,96.250', '2026-09-23,95.410', '2026-09-24,94.950', '2026-09-25,94.925'] (纳斯达克官网权威 tradesTable 末行仍为 09/24/2026, 94.95,totalRecords=81)

  • TLT/AGG 因此被写入 2026-09-25(TLT 79.095 / AGG 94.925),条数 81 → 82。
  • 危害被放大:合并规则是「已有日期不覆盖」(不补数红线),所以这个"伪收盘"

会永久留在库里,污染 09-25 的债券日回报与 L0-3 债券腿 —— 直接违反 「不制造当日尚未发生的价格」。

根因

scripts/update_bond_etf.py 只按日期做增量合并,没有任何"该日是否已收盘"的判定。

修复

新增会话完成判定与过滤:

def _is_session_final(d, now=None):
    """美股 16:00 ET 收盘(夏令时 20:00Z / 冬令时 21:00Z)→ 保守取 UTC 21:00。
    now_utc >= D 21:00Z 才算"最终收盘"。"""

def filter_session_final(series, now=None):   # 拆「最终收盘」与「盘中未完成」

merge_asset(..., now=None, drop_dates=None):

  1. 纳斯达克与东财两侧都过滤非最终收盘日期 → 进 provisional_dropped(不写入);
  2. 旧文件中非最终收盘日期同样被剪除(可回滚同轮已污染的行);
  3. drop_dates = 上一轮 payload 的 provisional_dropped.dates → 剪除历史遗留的盘中伪收盘并重取真值(自愈),由 main() 读取旧 payload 自动传入。

验证(真实数据回滚 + 自愈)

TLT: 82 天 → 81 天|最新 2026-09-24,79.42
   ⚠ 盘中未完成、未并入: ['2026-09-25']
AGG: 82 天 → 81 天|最新 2026-09-24,94.95
   ⚠ 盘中未完成、未并入: ['2026-09-25']
交叉验证: 两源真实收盘一致(≤0.01)(重叠 81 日)
  • 数据/bond_agg.json.provisional_dropped = {dates:[2026-09-25], rule:"…[待验证]"};
  • 面板 09-25 行的 tlt/agg 已清空(该行 lbma_priced=False、trading_day=False,不计入任何统计);
  • 09-25 收盘发布后,下一轮会正常并入(UTC 21:00Z 之后判定通过)。

三、同步与自检

项变更
驾驶舱头部面板规模84 行 → 85 行/区间 06-01→09-25
驾驶舱页脚日期2026-09-25 → 2026-09-26
驾驶舱 §〇·五 复盘地图99 → 100 直属(新增 09-25 盘前简报)
驾驶舱 §九新增 v5.2.1 版本记录(本报告)
复盘新增复盘/2026-09-25 盘前简报.md(review_write.py 落盘,✔ 导航页可直达)
排版同步doc_sync_check --strict rc=0 全绿
架构自检arch_check 10/10 ✔(死链 0 / 孤儿 0 / 0 个点不到)

回归测试(新增 3 项)

类测试断言
AuxSourceTeststest_aux_newer_than_target_still_falls_back二级源含 目标日 + 更晚日期 时回退仍生效;vix_src == "CBOE 官方日线 CSV";权威前值不再标 [待验证]
BondLegTeststest_intraday_bar_is_not_merged_as_close盘中(UTC 15:57)的 09-25 日线不入库,进 provisional_dropped
BondLegTeststest_post_close_bar_is_merged_and_marked_row_is_self_healed收盘后正常并入;上轮标记的伪收盘被剪除并重取真值

测试批次(iSH 必须分批/串行):BondLegTests+AuxSourceTests 11 OK; DocSyncTests+PathGuardTests 8 OK;PatternAbcTests+RegimeWfTests+PaperShortReduceTests 13 OK; PaperEngineTests 5 OK;PipelineSafetyTests 逐项运行。


四、回滚点

  • /var/minis/shared/backup/DUCKERRY_pre_auxvixfix_20260925/
  • dkanalysis.py(md5 050b6b3459fb5976fb9b7a28cead3121)
  • update_bond_etf.py(md5 2699d83443dd3cce29b590cd8191390b)
  • bond_agg.json / bond_tlt.json(含 09-25 伪收盘的污染版)
  • md5_before.txt

五、遗留(未变)

  • [P1] 09-25 LBMA PM / 债券腿收盘未发布 → 09-25 预测批次保持 pending。
  • [P1] 事件日历只覆盖到 09-24 → 前向事件覆盖缺失。
  • [P2] 美股指数二级源为东财单家(与 FRED 79→81 日逐日一致)→ 集中度 [待验证]。
  • [待验证] _is_session_final 的 UTC 21:00 保守界、provisional_dropped 规则本身均未经过长期样本外验证;

半日市(如感恩节翌日 13:00 ET 收盘)会用更早的收盘时间 → 当前规则更保守(不会误并入),方向安全。